/*
* Copyright (c) 2021 Talkweb Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "service_string.h"
#include<stdlib.h>
#include<stdio.h>

int32_t service_str2uint(char *input, uint8_t input_len, uint32_t *output)
{
    char buf[32];
    uint8_t i;
    uint8_t num;
    unsigned int ret_val;
    if (NULL == input)
        return 0;

    i = 0;
    while (i < input_len + 1)
    {
        if ((input[i] >= '0') && (input[i] <= '9'))
            buf[i] = input[i];
        else if ((input[i] >= 'a') && (input[i] <= 'f'))
        {
            buf[i] = input[i];
        }
        else if ((input[i] >= 'A') && (input[i] <= 'F'))
        {
            buf[i] = input[i] - 'A' + 'a';
        }
        else if (input[i] == 0)
        {
            buf[i] = 0;
            i++;
            break;
        }
        else
        {
            *output = 0;
            ret_val = 0;
            return RET_USER_INPUT_OUT_RANGE;
        }
        i++;
    }

    num = i - 1;
    ret_val = 0;
    for (i = 0; i < num; i++)
    {
        ret_val = ret_val * 10 + buf[i] - '0';
        if(ret_val>4294967295)
            return 0;
    }
    
    *output = ret_val;
    if(input_len>10)
        return 0;
    return RET_SUCCESS;
}

int32_t service_str2uint64(char *input, uint8_t input_len, uint64_t *output)
{
    char buf[64];
    uint8_t i;
    uint8_t num;
    uint64_t ret_val;
    if (NULL == input)
        return 0;
    if (input_len > 20) {
        *output = 0;
        return 0;
    }

    i = 0;
    while (i < input_len+1)
    {
        /* Format it */
        if ((input[i] >= '0') && (input[i] <= '9'))
            buf[i] = input[i];
        else if ((input[i] >= 'a') && (input[i] <= 'f'))
        {
            buf[i] = input[i];
        }
        else if ((input[i] >= 'A') && (input[i] <= 'F'))
        {
            buf[i] = input[i] - 'A' + 'a';
        }
        else if (input[i] == 0)
        {
            buf[i] = 0;
            i++;
            break;
        }
        else
            return 0;

        i++;
    }

    num = i - 1;
    ret_val = 0;
    for (i = 0; i < num; i++)
    {
        ret_val = ret_val * 10 + buf[i] - '0';
    }
    *output = ret_val;
    return 0;
}

int32_t service_uint2str(uint32_t input, char *output, uint8_t *output_len)
{
    sprintf(output,"%u",input);
    *output=strlen(output);
    return RET_SUCCESS;
}

int32_t service_int2hexstr(int32_t input, char *output, uint8_t *output_len)
{
    if (input >= 0) {
        sprintf(output, "0x%x", input);
    }
    else
    {
        sprintf(output, "-0x%x", -input);
        printf("efr44\n");
    }
    *output_len=strlen(output);
    return RET_SUCCESS;
}

int32_t service_uint642str(uint64_t input, char *output, uint8_t *output_len)
{
    int i, j;
    uint64_t sign;
    *output_len=0;

    char output_temp[21]={0};
    if ((sign = input) < 0) 
        input = -input;         
    i = 0;
    do
    {
        output_temp[i++] = input % 10 + '0'; 
        (*output_len)++;
    } while ((input /= 10) > 0);   
    if (sign < 0)
        output_temp[i++] = '-';
    output_temp[i] = '\0';
    for (j = i-1; j >= 0; j--) {
        output[i-1-j] = output_temp[j];
    }
    output[i] = '\0';
    return RET_SUCCESS;
}

int32_t service_int2str(int32_t input, char *output, uint8_t *output_len)
{
    sprintf(output,"%d",input);
    *output_len=strlen(output);
    return RET_SUCCESS;
}

int32_t service_hex2str(uint8_t *input, uint32_t input_len, char *output, uint8_t lowercase)
{
    char temp[3]={0};
    size_t i;
    for (i = 0; i < input_len; i++)
    {
        if (input[i] > 0xf) {
            if (lowercase)
                sprintf(temp, "%x", input[i]);
            else
                sprintf(temp, "%X", input[i]);
        }
        else {
            if (lowercase)
                sprintf(temp, "0%x", input[i]);
            else
                sprintf(temp, "0%X", input[i]);
        }
        strcat(output, temp);
        memset(temp, 0, 3);
    }
    
     return RET_SUCCESS;
}

int32_t service_str2hex(char *input, uint32_t input_len, uint8_t *output)
{
    size_t i;
    size_t j=0;
    uint8_t first=0;
    uint8_t second=0;

    int flag=1;
    if(input[0]=='-') {
        first='-';
        flag=1;
    }
    
    for (; i < input_len; i=i+2)
    {
        if (flag)
            first = 0;
        else
        {
            if ((input[i] >= '0') && (input[i] <= '9'))
                first = input[i] - '0';
            else if ((input[i] >= 'a') && (input[i] <= 'f'))
            {
                first = input[i] - 'a' + 10;
            }
            else if ((input[i] >= 'A') && (input[i] <= 'F'))
            {
                first = input[i] - 'A' + 10;
            }
            else
            {
                return RET_USER_INPUT_OUT_RANGE;
            }
        }
        if ((input[i + 1] >= '0') && (input[i + 1] <= '9'))
            second = input[i + 1] - '0';
        else if ((input[i + 1] >= 'a') && (input[i + 1] <= 'f'))
        {
            second = input[i + 1] - 'a' + 10;
        }
        else if ((input[i + 1] >= 'A') && (input[i + 1] <= 'F'))
        {
            second = input[i + 1] - 'A' + 10;
        }
        else
        {
            return RET_USER_INPUT_OUT_RANGE;
        }
        output[j++]=first*16+second;
    }

    if(input_len % 2!=0)
        return RET_USER_INPUT_OUT_RANGE;
    
    return RET_SUCCESS;
}

int32_t service_strdup(tiot_sysdep_portfile_t *sysdep, char **dest, char *src)
{
    if (*dest != NULL) {
        sysdep->service_sysdep_free(*dest);
        *dest = NULL;
    }

    *dest = sysdep->service_sysdep_malloc((uint32_t)(strlen(src) + 1));
    if (*dest == NULL) {
        return RET_SYS_DEPEND_MALLOC_FAILED;
    }
    sysdep->service_sysdep_memset(*dest, 0, strlen(src) + 1);
    sysdep->service_sysdep_memcpy(*dest, src, strlen(src));

    return RET_SUCCESS;
}

int32_t service_sprintf(tiot_sysdep_portfile_t *sysdep, char **dest, char *fmt, char *src[], uint8_t count)
{
     char *buffer = NULL, *value = NULL;
    uint8_t idx = 0, percent_idx = 0;
    uint32_t buffer_len = 0;

    buffer_len += strlen(fmt) - 2 * count;
    for (percent_idx = 0; percent_idx < count; percent_idx++) {
        value = (*(src + percent_idx) == NULL) ? ("") : (*(src + percent_idx));
        buffer_len += strlen(value);
    }

    buffer = sysdep->service_sysdep_malloc(buffer_len + 1);
    if (buffer == NULL) {
        return RET_SYS_DEPEND_MALLOC_FAILED;
    }
    sysdep->service_sysdep_memset(buffer, 0, buffer_len + 1);

    for (idx = 0, percent_idx = 0; idx < strlen(fmt);) {
        if (fmt[idx] == '%' && fmt[idx + 1] == 's') {
            value = (*(src + percent_idx) == NULL) ? ("") : (*(src + percent_idx));
            sysdep->service_sysdep_memcpy(buffer + strlen(buffer), value, strlen(value));
            percent_idx++;
            idx += 2;
        } else {
            buffer[strlen(buffer)] = fmt[idx++];
        }
    }
    *dest = buffer;
    return RET_SUCCESS;
}

int32_t service_json_value(tiot_sysdep_portfile_t *sysdep, const char *input, uint32_t input_len, const char *key, uint32_t key_len, char **value,
                        uint32_t *value_len)
{
    uint32_t idx = 0;

    for (idx = 0; idx < input_len; idx++) {
        if (idx + key_len >= input_len) {
            return RET_USER_INPUT_JSON_PARSE_FAILED;
        }
        if ((sysdep->service_sysdep_memcmp(&input[idx], key, key_len) == 0) &&
            ((idx > 0) && (input[idx - 1] == '"')) &&
            ((idx + key_len < input_len) && (input[idx + key_len] == '"'))) {
            idx += key_len;
            /* shortest ":x, or ":x} or ":x] */
            if ((idx + 2 >= input_len) ||
                (input[idx + 1] != ':')) {
                return RET_USER_INPUT_JSON_PARSE_FAILED;
            }
            idx += 2;
            if (input[idx] == '"') {
                *value = (char *)&input[++idx];
                for (; idx < input_len; idx++) {
                    if ((input[idx] == '"')) {
                        *value_len = (uint32_t)(idx - (*value - input));
                        return RET_SUCCESS;
                    }
                }
            } else if (input[idx] == '{' || input[idx] == '[') {
                char start = input[idx];
                char end = (start == '{') ? ('}') : (']');
                uint8_t count = 0;
                *value = (char *)&input[idx];
                for (; idx < input_len; idx++) {
                    if ((input[idx] == start)) {
                        count++;
                    } else if ((input[idx] == end)) {
                        if (--count == 0) {
                            *value_len = (uint32_t)(idx - (*value - input) + 1);
                            return RET_SUCCESS;
                        }
                    }
                }
            } else {
                *value = (char *)&input[idx];
                for (; idx < input_len; idx++) {
                    if ((input[idx] == ',' || input[idx] == ']' || input[idx] == '}')) {
                        *value_len = (uint32_t)(idx - (*value - input));
                        return RET_SUCCESS;
                    }
                }
            }
        }
    }

    return RET_USER_INPUT_JSON_PARSE_FAILED;
}

int32_t service_utc2date(uint64_t utc, int8_t zone, service_date_t *date)
{
    uint32_t day_sec = 0, day_num = 0;
    uint64_t utc_zone_s = 0;

#define DAYS_IN_YEAR(year)        (IS_LEAP_YEAR(year) ? 366 : 365)
#define IS_LEAP_YEAR(year)        (!((year) % 400) || (((year) % 100) && !((year) % 4)))
#define DAYS_IN_MONTH(lpyr, mon)  ((mon == 1)?(28 + lpyr):((mon > 6)?(((mon - 1) & 1)?(30):(31)):((mon & 1)?(30):(31))))

    date->msec = utc % 1000;
    utc_zone_s = (utc / 1000) + (zone * 60 * 60);

    day_sec = utc_zone_s % (24 * 60 * 60);
    day_num = utc_zone_s / (24 * 60 * 60);

    date->sec = day_sec % 60;
    date->min = (day_sec % 3600) / 60;
    date->hour = day_sec / 3600;

    date->year = 1970;
    while (day_num >= DAYS_IN_YEAR(date->year)) {
        day_num -= DAYS_IN_YEAR(date->year);
        date->year++;
    }

    date->mon = 0;
    while (day_num >= DAYS_IN_MONTH(IS_LEAP_YEAR(date->year), date->mon)) {
        day_num -= DAYS_IN_MONTH(IS_LEAP_YEAR(date->year), date->mon);
        date->mon++;
    }
    date->mon++;
    date->day = day_num + 1;

    return 0;
}

int32_t service_strcat(tiot_sysdep_portfile_t *sysdep, char **dest, char *src1, char *src2)
{
    uint32_t dest_len = 0;
    char *tmp_dest = NULL;

    dest_len = strlen(src1) + strlen(src2) + 1;
    tmp_dest = (char *)malloc(dest_len);
    if (tmp_dest == NULL) {
        return RET_SYS_DEPEND_MALLOC_FAILED;
    }
    memset(tmp_dest, 0, dest_len);
    strcat(tmp_dest,src1);
    strcat(tmp_dest,src1);

    if (*dest != NULL) {
        sysdep->service_sysdep_free(*dest);
        *dest = NULL;
    }
    *dest = tmp_dest;

    return RET_SUCCESS;
}
